问题: 什么是正则表达式的分组,如何用()实现简单分组?

👇 点击展开/折叠 面试背诵模板(建议先背这个) 正则分组指用圆括号 `()` 将模式中的子表达式括起来,将其视为一个整体单元。核心作用有两方面:一是组合量化,让量词(如 `+`、`*`)作用于整个括号内的子表达式(如 `(ab)+` 可匹配 `abab`);二是捕获提取,匹配成功后,括号内匹配的具体子串会被保存,可通过 `group(1)`、`group(2)` 等编号提取。分组编号默认按左括号出现的顺序从 1 开始递增。

捕获组编号规则与代码示例

括号按左括号出现的先后顺序编号(从 1 开始)。group(0) 或 group() 返回完整匹配结果。

1
2
3
4
5
6
7
8
9
import re
text = "2024-10-01"
pattern = r'(\d{4})-(\d{2})-(\d{2})'
match = re.search(pattern, text)

print(match.group(0)) # '2024-10-01'(完整匹配)
print(match.group(1)) # '2024'(第一个括号:年份)
print(match.group(2)) # '10'(第二个括号:月份)
print(match.group(3)) # '01'(第三个括号:日期)

分组提取与 findall 的行为差异

当使用 re.findall() 且模式中包含多个捕获组时,返回的不再是字符串列表,而是元组列表,每个元组对应一个匹配项中各分组的内容。

1
2
3
4
5
6
7
text = "日期: 2024-10-01, 2025-12-31"
results = re.findall(r'(\d{4})-(\d{2})-(\d{2})', text)
print(results) # [('2024', '10', '01'), ('2025', '12', '31')]

# 遍历提取
for year, month, day in results:
print(f"年: {year}, 月: {month}, 日: {day}")

基础应用:提取用户名与域名

1
2
3
4
5
text = "联系: zhangsan@qq.com"
match = re.search(r'(\w+)@(\w+\.\w+)', text)
if match:
print(match.group(1)) # 'zhangsan'(用户名)
print(match.group(2)) # 'qq.com'(域名)

非捕获分组 (?:...)(拓展对比)

若只需组合量化而无需提取子串,可使用 (?:...) 非捕获分组,避免占用编号并提升性能。

写法 是否捕获 适用场景
(pattern) ✅ 是(默认捕获) 需要提取括号内匹配的子串
(?:pattern) ❌ 否 仅需将子表达式作为整体量化,无需提取
1
2
3
# 非捕获分组示例:匹配 'go' 或 'goo',但不提取
pattern = r'go(?:o)?'
print(re.findall(pattern, 'go goo')) # ['go', 'goo']